# A tibble: 6 × 6
group1 group2 id var1 var2 var3
<chr> <chr> <chr> <dbl> <int> <fct>
1 A X id1 -0.560 1 a
2 A Y id2 -0.230 2 b
3 A Z id3 1.56 3 c
4 B X id4 0.0705 4 d
5 B Y id5 0.129 5 e
6 B Z id6 1.72 6 f
results: asis
Don’t forget!
Write #| results: asis at the beginning of the chunk or results='asis' in the chunk options.
Notice that the above output is not prefixed with “[1]” as in “[1] -0.5604756”. This is because cat() is used internally for non-list columns to avoid unnecessary prefixes such as “[1]” in the output. On the other hand, print() is used for list columns.
tabset_vars, output_vars
Multiple tabset_vars and output_vars are acceptable. For multiple tabset_vars, they are displayed nested.
In render_tabset(), cat() is used to output for columns that are not list types. However, if cat() is used, factor is output as an integer. So, if factor is included in output_vars, it is converted internally to string.
x <-factor("a")# default factor outputprint(x)
[1] a
Levels: a
# Using `cat()` for factor results in unexpected outputcat(x)
1
# `render_tabset()` converts factor to string# and then executes cat() as follows.cat(as.character(x))
a
layout
How can I display the content in a tabset horizontally? In quarto, layout-ncol can be used.
Oops, the entire tabset is now a third of the width. We want the content within to be displayed side by side without changing the width of the tabset. This is where the layout argument comes in handy.
If you are viewing on a smartphone, the layout may not be displayed correctly.
The layout argument is intended for very simple use cases, so complex layouts may not work.
heading_levels
Use the heading_levels argument if you want the heading to be displayed as normal headings instead of tabsets. heading_levels and tabset_vars correspond in order. Each tabset_vars is expressed as the heading of specified in heading_levels. If the element of heading_levels is NA, then the element of its tabset_vars is represented as tabset.
Example 1
For example, group1 should be tabset and group2 should be h4 heading.
Although it is preferable for the heading to be progressively larger due to the structure of the chapter, but can be the same or progressively smaller.
This section shows more practical examples. Use the mtcars dataset, grouped by cyl and am, to create figures and tables showing the relationship between wt and mpg. render_tabset() was originally created to represent figures and tables as tabsets, with nested data frames as input. Nesting approach is useful when the same operation is performed on each group.
nest() + map()
We shows how to use tidyr::nest() and purrr::map() combination.
Figures and tables have been created for the fig and tbl columns respectively. Also note that the group variables cly and am are not ordered in regular ascending order. They are arranged in order of appearance. In Next step, specifying cly and am in tabset_vars in render_tabset() automatically executes arrange(cly, am) internally. So don’t worry.
Tip
We did not run arrange(cly, am) in this example for the sake of example, but in practice it is better to run arrange(cly, am) in the pipeline to make it easier to identify each group.
This way, the values of other columns in the list() can be used freely. (In the nest() + map() method, it was necessary to define in advance which columns to use when calling in the map()).
The outputs are grouped rowwise and already sorted by cly and am.
Figures
In the following, df2 is used. (Works in the same way in df2_rowwise).
You can use {plotly} to create interactive figures.
First, let’s create figures using {plotly}. Simply apply plotly::ggplotly() to the already created ggplot object. Then it is passed to htmltools::div().
df4 <- df2 |>mutate(fig_plotly =map( fig, \(p) {ggplotly( p,height =700# make large figure, for example ) |> htmltools::div() } ) ) |>select(cyl, am, fig_plotly)df4
When outputting tables or figures that use javascript (such as {plotly}, {leaflet}, {DT}, {reactable}, etc.), it seems javascript dependencies need to be resolved. The easiest way seems to output them once in a separate chunk.
As above, this example prepares a chunk that executes only plot_ly(). Set #| include: false so that this chunk and its output will not appear on the report.
```{r}#| include: falseplot_ly()```
Then execute render_tabset() as in basic usage. Add column: page-right chunk option to increase the size of the figure.
Here we will show you how to use render_tabset() in a popular package for rendering tables. This example uses knitr::kable(), gt::gt(), gt::opt_interactive(), flextable::flextable(), DT::datatable(), reactable::reactable() and tinytable::tt().
tables <- df2 |>select(cyl, am, data) |>mutate(kable =map(data, knitr::kable),gt =map(data, gt::gt),gt_interactive =map(gt, gt::opt_interactive),tt =map(data, tinytable::tt),flex =map_chr( data, \(data) { flextable::flextable(data) |> knitr::knit_print() } ),DT =map( data, \(data) { DT::datatable(data) |> htmltools::div() } ),reac =map( data, \(data) { reactable::reactable(data) |> htmltools::div() } ),section_kable ="#### knitr::kable()",section_gt ="#### gt::gt()",section_gt_interactive =paste("#### gt::gt() |> gt::opt_interactive()","(and run in a separate chunk)" ),section_tt ="#### tinytable::tt()",section_flex =paste("#### flextable::flextable() |> knitr::knit_print()","(using map_chr())" ),section_DT =paste("#### DT::datatable() |> htmltools::div()","(and run in a separate chunk)" ),section_reac =paste("#### reactable::reactable() |> htmltools::div()","(and run in a separate chunk)" ) )tables
knitr::kable(), gt::gt(), and tinytable::tt() are the simplest.
The output of flextable::flextable() is managed by the method knitr::knit_print(). After execution, raw HTML is obtained, which is turned into a character type column using map_chr().
gt::opt_interactive(), {DT} and {reactable} use javascript. They should be wrapped with htmltools::div(), except for gt::opt_interactive(), and run in a separate chunk to resolve javascript dependencies. Don’t forget #| include: false.
DT::datatable() |> htmltools::div() (and run in a separate chunk)
reactable::reactable() |> htmltools::div() (and run in a separate chunk)
Session Info
# save the session info as an objectsess <- sessioninfo::session_info(pkgs ="attached")# inject the quarto infosess$platform$quarto <-paste( quarto::quarto_version(),"@", fs::path_real(quarto::quarto_path()))# print it outsess
---title: "Demo: render_tabset()"format: html: code-tools: true embed-resources: true toc: true toc-location: left toc-expand: truedate: last-modifiedknitr: opts_chunk: message: false---## Basic usageHere are basic examples. First, load the libraries used in this demo and create sample data.```{r}#| message: falselibrary(quartabs)library(tibble)library(dplyr)library(purrr)library(tidyr)library(knitr)library(gt)library(DT)library(reactable)library(flextable)library(plotly)library(leaflet)library(htmltools)library(janitor)library(tinytable)set.seed(123)# sample datadf1 <-tibble(group1 =c(rep("A", 3), rep("B", 3)),group2 =rep(c("X", "Y", "Z"), 2),id =paste0("id", 1:6),var1 =rnorm(6),var2 =1:6,var3 =factor(letters[1:6]))df1```### results: asis::: {.callout-note icon="true"}## Don't forget!Write `#| results: asis` at the beginning of the chunk or `results='asis'` in the chunk options.:::``` {{r}}#| results: asisdf1 |> render_tabset(id, var1)``````{r}#| results: asis#| echo: falsedf1 |>render_tabset(id, var1)```This is equal to the following.```{r, results='asis'}#| echo: fenceddf1 |> render_tabset(id, var1)```:::{.callout-tip appearance='default' icon=true}## `cat()` or `print()`Notice that the above output is not prefixed with "[1]" as in "[1] -0.5604756". This is because `cat()` is used internally for non-list columns to avoid unnecessary prefixes such as "[1]" in the output. On the other hand, `print()` is used for list columns.:::### `tabset_vars`, `output_vars`Multiple `tabset_vars` and `output_vars` are acceptable. For multiple `tabset_vars`, they are displayed nested.```{r}#| results: asisdf1 |>render_tabset(c(group1, group2), c(var1, var2, var3))```Characters or [tidyselect](https://dplyr.tidyverse.org/reference/dplyr_tidy_select.html) can also be used for `tabset_vars` and `output_vars`.```{r}#| results: asisvars <-c("var1", "var2", "var3")df1 |>render_tabset(c("group1", "group2"), vars)```### Factor outputIn `render_tabset()`, `cat()` is used to output for columns that are not list types.However, if `cat()` is used, factor is output as an integer. So, if factor is included in `output_vars`, it is converted internally to string.```{r}#| echo: truex <-factor("a")# default factor outputprint(x)# Using `cat()` for factor results in unexpected outputcat(x)# `render_tabset()` converts factor to string# and then executes cat() as follows.cat(as.character(x))```### `layout`How can I display the content in a tabset horizontally?In quarto, `layout-ncol` can be used.```{r}#| results: asis#| layout-ncol: 3df1 |> render_tabset(c(group1, group2), c(var1, var2, var3))``````{r}#| results: asis#| layout-ncol: 3#| echo: falsedf1 |>render_tabset(c(group1, group2), c(var1, var2, var3))```Oops, the entire tabset is now a third of the width.We want the content within to be displayed side by side without changing the width of the tabset.This is where the `layout` argument comes in handy.```{r}#| results: asisdf1 |>render_tabset(c(group1, group2),c(var1, var2, var3),layout ="::: {layout-ncol=3}" )```For more information about `layout`, see [Custom Layouts](https://quarto.org/docs/authoring/figures.html#complex-layouts). :::{.callout-warning}* If you are viewing on a smartphone, the layout may not be displayed correctly.* The `layout` argument is intended for very simple use cases, so complex layouts may not work.:::### `heading_levels`Use the `heading_levels` argument if you want the heading to be displayed as normal headings instead of tabsets. `heading_levels` and `tabset_vars` correspond in order.Each `tabset_vars` is expressed as the heading of specified in `heading_levels`.If the element of `heading_levels` is `NA`, then the element of its `tabset_vars` is represented as tabset.#### Example 1 For example, `group1` should be tabset and `group2` should be h4 heading.```{r}#| results: asisdf1 |>render_tabset(c(group1, group2),c(var1, var2, var3),heading_levels =c(NA, 4) )```#### Example 2Conversely, `group1` should be heading 4 and `group2` should be tabset.```{r}#| results: asisdf1 |>render_tabset(c(group1, group2),c(var1, var2, var3),heading_levels =c(4, NA) )```#### Example 3Set `group1` to heading 4 and `group2` to heading 5 (no tabset).```{r}#| results: asisdf1 |>render_tabset(c(group1, group2),c(var1, var2, var3),heading_levels =c(4, 5) )```#### Example 4Although it is preferable for the heading to be progressively larger due to thestructure of the chapter, but can be the same or progressively smaller.```{r}#| results: asisdf1 |>render_tabset(c(group1, group2),c(var1, var2, var3),heading_levels =c(5, 4) )```#### Example 5`header_levels` can work with `layout`.```{r}#| results: asisdf1 |>render_tabset(c(group1, group2),c(var1, var2, var3),layout ="::: {layout-ncol=3}",heading_levels =c(4, NA) )```### `pills````{r}#| results: asisdf1 |>render_tabset(c(group1, group2),c(var1, var2, var3),pills =TRUE )```### `tabset_width````{r}#| results: asis#| layout-ncol: 2df1_long_label <- df1 |>mutate(group1 =paste("This is a long label for", group1) )df1_long_label |>render_tabset(c(group1, group2),c(var1, var2, var3),tabset_width ="fill" )``````{r}#| results: asis#| layout-ncol: 2df1_long_label |>render_tabset(c(group1, group2),c(var1, var2, var3),tabset_width ="justified" )```## Figures and tablesThis section shows more practical examples.Use the `mtcars` dataset, grouped by `cyl` and `am`, to create figures and tables showing the relationship between `wt` and `mpg`.`render_tabset()` was originally created to represent figures and tables as tabsets, with nested data frames as input.Nesting approach is useful when the same operation is performed on each group.### `nest() + map()`We shows how to use `tidyr::nest()` and `purrr::map()` combination.For more information on the nest, see follows:- [Nested data](https://tidyr.tidyverse.org/articles/nest.html)- [23 Model basics](https://r4ds.had.co.nz/model-basics.html)- [TokyoR #108 Nested Data Handling](https://speakerdeck.com/kilometer/tokyor-number-108-nesteddatahandling)- [nested data で ggplot](https://qiita.com/kilometer/items/7f99c0a9af6d7ce43485)```{r}# new sample datadf2 <- mtcars |># make groups more explicitmutate(cyl =paste("cyl:", cyl),am =paste("am:", am) ) |># nestnest(.by =c(cyl, am)) |>mutate(# create titles for figurestitle =paste(cyl, am, sep =", "),# create scatter plotsfig =map2( data, title, \(data, title) { data |>ggplot(aes(wt, mpg)) +geom_point() +labs(title = title) } ),# create tablestbl =map( data, \(data) { data |>select(wt, mpg) |> knitr::kable() } ) )df2```Figures and tables have been created for the `fig` and `tbl` columns respectively.Also note that the group variables `cly` and `am` are not ordered in regular ascending order. They are arranged in order of appearance.In Next step, specifying `cly` and `am` in `tabset_vars` in `render_tabset()` automatically executes `arrange(cly, am)` internally.So don't worry.:::{.callout-tip icon=true}We did not run `arrange(cly, am)` in this example for the sake of example,but in practice it is better to run `arrange(cly, am)` in the pipeline to make it easier to identify each group.```{r}df2 |>arrange(cyl, am)```:::### `nest_by() + list()`Another method is to use `dplyr::nest_by()` and `list()`. This approach is simpler and more intuitive to write.For more information, see follows:- [Row-wise operations](https://dplyr.tidyverse.org/articles/rowwise.html)```{r}df2_rowwise <- mtcars |># make groups more explicitmutate(cyl =paste("cyl:", cyl),am =paste("am:", am) ) |># nestnest_by(cyl, am) |>mutate(# create titles for figurestitle =paste(cyl, am, sep =", "),# create scatter plotsfig =list( data |>ggplot(aes(wt, mpg)) +geom_point() +labs(title = title) ),# create tablestbl =list( data |>select(wt, mpg) |> knitr::kable() ) )df2_rowwise```This way, the values of other columns in the `list()` can be used freely. (In the `nest() + map()` method, it was necessary to define in advance which columns to use when calling in the `map()`).The outputs are grouped rowwise and already sorted by `cly` and `am`.### FiguresIn the following, `df2` is used. (Works in the same way in `df2_rowwise`).```{r}#| results: asisdf2 |>render_tabset(c(cyl, am), fig)```### Tables```{r}#| results: asisdf2 |>render_tabset(c(cyl, am), tbl)```### Figures and tables```{r}#| results: asisdf2 |>render_tabset(c(cyl, am), c(fig, tbl))```### layoutUse the `layout` argument to display figure and table side by side with a width of 7:3.```{r}#| results: asisdf2 |>render_tabset(c(cyl, am), c(fig, tbl), layout ='::: {layout="[7, 3]"}')```## Advanced examples### Pre-saved figures<!-- Simply format the path to the saved figure like `` and excute `render_tabset()` as before. --><!-- ```{r} --><!-- # directory for saving figures --><!-- dir <- "C:/Users/Yusuke Sasaki/Documents/demo" --><!-- # new sample data --><!-- df3 <- df2 |>--><!-- mutate( --><!-- fig_path = file.path( --><!-- dir, --><!-- paste0(janitor::make_clean_names(title), ".png") --><!-- ), --><!-- # To make the return value a character vector, use `map2_chr()` --><!-- fig_path_md = map2_chr( --><!-- fig, --><!-- fig_path, --><!-- \(p, path) { --><!-- p <- p + --><!-- labs( --><!-- subtitle = path --><!-- ) --><!-- # save figure --><!-- ggsave(path) --><!-- # format path to markdown style --><!-- # caption can be omitted --><!-- return(str_glue("")) --><!-- } --><!-- ) --><!-- ) |>--><!-- select(cyl, am, fig_path_md) --><!-- df3 --><!-- ``` --><!-- Then execute `render_tabset()` as in basic usage. --><!-- ```{r} --><!-- #| results: asis --><!-- df3 |>--><!-- render_tabset(c(cyl, am), fig_path_md) --><!-- ``` --><!-- :::{.callout-tip} --><!-- ## `nest_by() + list({ <some complex code> })` --><!-- Replace the above `nest() + map()` method with `rowwise() + list()`. --><!-- ```{r} --><!-- #| error: true --><!-- # new sample data --><!-- df3_rowwise <- df2_rowwise |>--><!-- mutate( --><!-- fig_path = file.path( --><!-- dir, --><!-- paste0(janitor::make_clean_names(title), ".png") --><!-- ), --><!-- # To make the return value a character vector, use `map2_chr()` --><!-- fig_path_md = list( --><!-- p <- fig + --><!-- labs( --><!-- subtitle = fig_path --><!-- ) --><!-- # save figure --><!-- ggsave(fig_path) --><!-- # format path to markdown style --><!-- str_glue("") --><!-- ) --><!-- ) |>--><!-- select(cyl, am, fig_path_md) --><!-- ``` --><!-- An error occurred because we tried to create an intermediate object (`p`) or excute multiple operations that are not connected by a pipe in the `list()`. --><!-- In such cases, use `list({ <some complex code> })`. --><!-- ```{r} --><!-- df3_rowwise <- df2_rowwise |>--><!-- mutate( --><!-- fig_path = file.path( --><!-- dir, --><!-- paste0(janitor::make_clean_names(title), ".png") --><!-- ), --><!-- # To make the return value a character vector, use `map2_chr()` --><!-- fig_path_md = list({ --><!-- p <- fig + --><!-- labs( --><!-- subtitle = fig_path --><!-- ) --><!-- # save figure --><!-- ggsave(fig_path) --><!-- # format path to markdown style --><!-- str_glue("") --><!-- }) --><!-- ) |>--><!-- select(cyl, am, fig_path_md) --><!-- df3_rowwise --><!-- ``` --><!-- Then execute `render_tabset()` as in basic usage. --><!-- ```{r} --><!-- #| results: asis --><!-- df3_rowwise |>--><!-- render_tabset(c(cyl, am), fig_path_md) --><!-- ``` --><!-- ::: -->### PlotlyYou can use `{plotly}` to create interactive figures.First, let's create figures using `{plotly}`. Simply apply `plotly::ggplotly()` to the already created ggplot object. Then it is passed to `htmltools::div()`.```{r}df4 <- df2 |>mutate(fig_plotly =map( fig, \(p) {ggplotly( p,height =700# make large figure, for example ) |> htmltools::div() } ) ) |>select(cyl, am, fig_plotly)df4```:::{.callout-important appearance='default' icon=true}## Resolve javascript dependenciesWhen outputting tables or figures that use javascript (such as `{plotly}`, `{leaflet}`, `{DT}`, `{reactable}`, etc.), it seems javascript dependencies need to be resolved. The easiest way seems to output them once in a separate chunk.References:- [offline plots in for loops - github](https://github.com/plotly/plotly.R/issues/273)- [Using ggplotly and DT from a for loop in Rmarkdown - stackoverflow](https://stackoverflow.com/questions/60685631/using-ggplotly-and-dt-from-a-for-loop-in-rmarkdown/62599342#62599342)- [plotly objects are invisible in R Markdown - stackoverflow](https://stackoverflow.com/questions/75992729/plotly-objects-are-invisible-in-r-markdown):::As above, this example prepares a chunk that executes only `plot_ly()`. Set `#| include: false` so that this chunk and its output will not appear on the report.```{r}#| include: falseplot_ly()``````{r}#| include: false#| echo: falseplot_ly()```Then execute `render_tabset()` as in basic usage.Add `column: page-right` chunk option to increase the size of the figure.``` {{r}}#| results: asis#| column: page-rightdf4 |> render_tabset(c(cyl, am), fig_plotly)``````{r}#| results: asis#| column: page-right#| echo: falsedf4 |>render_tabset(c(cyl, am), fig_plotly)```### Leaflet<!-- Another example the above flow (wrap output with `htmltools::div()` and then creating dummy plot in a separate chunk and then `render_tabset()`) is Leaflet. In R, `{leaflet}` is useful for plotting map. It also serves as an introduction to the functionality of `{jprep.datasets}`, let's create and visualize dummy student addresses for Juku and Kids at the beginning of March. Note that for the purposes of this demo, the period is 2016 to 2023. --><!-- `jprep.datasets::main_buildings` contains the main school building for each period for each program. --><!-- ```{r} --><!-- sites <- main_buildings |>--><!-- # For demo, remaining up to the beginning of the month of March 2023. --><!-- filter(start_date <= as.Date("2024-03-05")) |> --><!-- filter(program %in% c("Juku", "Kids")) |>--><!-- filter(site != "Hongo") |># Not owned by J PREP --><!-- select(program, site, start_date, end_date, lon_site, lat_site) --><!-- sites |>--><!-- print(n = Inf) --><!-- ``` --><!-- The `start_date` and `end_date` indicate when the school building was used as the main location for that site. In particular, Jiyugaoka, Shibuya, and Kichijoji are shown to have moved multiple times. --><!-- Assign a color to each site for visualization. --><!-- This is an example of a maximum of 7 sites. --><!-- ```{r} --><!-- # Named vectors may not be handled correctly in addCircleMarkers(), --><!-- # which will be used later. So `unname()` is important. --><!-- pal <- unname(palette.colors()[2:8]) --><!-- hexs <- sites |>--><!-- distinct(site) |>--><!-- bind_cols(hex = pal) --><!-- ``` --><!-- Join to the `site` --><!-- ```{r} --><!-- sites_with_hex <- sites |>--><!-- left_join(hexs) --><!-- sites_with_hex --><!-- ``` --><!-- Get the first date of the academic year. --><!-- ```{r} --><!-- yr_starts <- calendar_jprep |>--><!-- slice_min(date, by = c(program, year)) |>--><!-- select(program, year, date) --><!-- yr_starts --><!-- ``` --><!-- Join main school buildings that existed at the beginning of each academic year. `dplyr::join_by()` is useful. --><!-- ```{r} --><!-- yr_starts_site <- --><!-- yr_starts |>--><!-- left_join( --><!-- sites_with_hex, --><!-- join_by( --><!-- program, --><!-- between(date, start_date, end_date) --><!-- ) --><!-- ) |>--><!-- select(program, year, site, hex, lon_site, lat_site) --><!-- yr_starts_site --><!-- ``` --><!-- How many sites per program each year? --><!-- ```{r} --><!-- yr_starts_site |>--><!-- count(program, year) --><!-- ``` --><!-- Create 10 dummy student data for each program, year, and site. Let's scatter them randomly around the school building. --><!-- ```{r} --><!-- dummy_students <- --><!-- yr_starts_site |>--><!-- mutate( --><!-- data = map2( --><!-- lon_site, --><!-- lat_site, --><!-- \(ln, lt) { --><!-- tibble( --><!-- lon = ln + rnorm(n = 10, sd = .01), --><!-- lat = lt + rnorm(n = 10, sd = .01) --><!-- ) --><!-- } --><!-- ) --><!-- ) |>--><!-- unnest(data) --><!-- dummy_students --><!-- ``` --><!-- Create a base leaflet. --><!-- ```{r} --><!-- p_base <- --><!-- leaflet() |>--><!-- # In this example, make it appear large --><!-- leaflet(width = 1200, height = 1600) |>--><!-- setView(lng = 139.67, lat = 35.6, zoom = 11) |>--><!-- # group: light --><!-- addProviderTiles(providers$CartoDB.Positron, group = "light") |>--><!-- # group: light (Railway highlighted) --><!-- addProviderTiles(providers$CartoDB.Positron, group = "light (Railway highlighted)") |>--><!-- addProviderTiles(providers$OpenRailwayMap, group = "light (Railway highlighted)") --><!-- ``` --><!-- Here is the main thing. Create a leaflet for each program and year. --><!-- ```{r} --><!-- leaflets <- dummy_students |>--><!-- nest(.by = c(program, year)) |>--><!-- mutate( --><!-- # to display the new year first in tabset --><!-- year = fct_rev(as.character(year)), --><!-- # create leaflet map --><!-- lf = map( --><!-- data, --><!-- \(data) { --><!-- # for site ordering --><!-- data <- data |>--><!-- mutate( --><!-- site = fct_sites(site) --><!-- ) |>--><!-- arrange(site) --><!-- # unique sites --><!-- sites <- data |>--><!-- distinct(site, lon_site, lat_site) --><!-- p_base |>--><!-- # add markers to each site --><!-- addMarkers( --><!-- data = sites, --><!-- lng = ~lon_site, --><!-- lat = ~lat_site, --><!-- label = ~site --><!-- ) |>--><!-- # each student --><!-- addCircleMarkers( --><!-- data = data, --><!-- lng = ~lon, --><!-- lat = ~lat, --><!-- opacity = 1, --><!-- fillOpacity = .7, --><!-- radius = 4, --><!-- weight = 3, --><!-- color = ~hex, --><!-- label = ~paste(site, lon, lat, sep = "<br>") |>lapply(htmltools::HTML), --><!-- group = ~site --><!-- ) |>--><!-- addLayersControl( --><!-- baseGroups = c("light", "light (Railway highlighted)"), --><!-- overlayGroups = sites$site, --><!-- options = layersControlOptions(collapsed = FALSE) --><!-- ) |>--><!-- htmltools::div() --><!-- } --><!-- ) --><!-- ) --><!-- leaflets --><!-- ``` --><!-- As described in the plotly section, output only the leaflet in a separate chunk. We plot `p_base` (You think `leaflet()` is also good instead of `p_base`, but it does not work well) --><!-- . Don't forget `#| include: false` to avoid displaying output. --><!-- ```{r} --><!-- #| include: false --><!-- p_base --><!-- ``` --><!-- ```{r} --><!-- #| include: false --><!-- #| echo: false --><!-- p_base --><!-- ``` --><!-- Then execute `render_tabset()` as in basic usage. --><!-- Add `column: screen-inset` chunk option to see larger at the width of the screen. --><!-- ``` {{r}} --><!-- #| results: asis --><!-- #| column: screen-inset --><!-- leaflets |>--><!-- render_tabset(c(program, year), lf) --><!-- ``` --><!-- ```{r} --><!-- #| results: asis --><!-- #| column: screen-inset --><!-- #| echo: false --><!-- leaflets |>--><!-- render_tabset(c(program, year), lf) --><!-- ``` -->### TablesHere we will show you how to use `render_tabset()` in a popular package for rendering tables.This example uses `knitr::kable()`, `gt::gt()`, `gt::opt_interactive()`, `flextable::flextable()`, `DT::datatable()`, `reactable::reactable()` and `tinytable::tt()`.```{r}tables <- df2 |>select(cyl, am, data) |>mutate(kable =map(data, knitr::kable),gt =map(data, gt::gt),gt_interactive =map(gt, gt::opt_interactive),tt =map(data, tinytable::tt),flex =map_chr( data, \(data) { flextable::flextable(data) |> knitr::knit_print() } ),DT =map( data, \(data) { DT::datatable(data) |> htmltools::div() } ),reac =map( data, \(data) { reactable::reactable(data) |> htmltools::div() } ),section_kable ="#### knitr::kable()",section_gt ="#### gt::gt()",section_gt_interactive =paste("#### gt::gt() |> gt::opt_interactive()","(and run in a separate chunk)" ),section_tt ="#### tinytable::tt()",section_flex =paste("#### flextable::flextable() |> knitr::knit_print()","(using map_chr())" ),section_DT =paste("#### DT::datatable() |> htmltools::div()","(and run in a separate chunk)" ),section_reac =paste("#### reactable::reactable() |> htmltools::div()","(and run in a separate chunk)" ) )tables````knitr::kable()`, `gt::gt()`, and `tinytable::tt()` are the simplest.The output of `flextable::flextable()` is managed by the method `knitr::knit_print()`. After execution, raw HTML is obtained, which is turned into a character type column using `map_chr()`.`gt::opt_interactive()`, `{DT}` and `{reactable}` use javascript. They should be wrapped with `htmltools::div()`, except for `gt::opt_interactive()`, and run in a separate chunk to resolve javascript dependencies. Don't forget `#| include: false`.```{r}#| include: falsegt::gt(mtcars) |> gt::opt_interactive()DT::datatable(mtcars)reactable::reactable(mtcars)``````{r}#| include: false#| echo: falsegt::gt(mtcars) |> gt::opt_interactive()DT::datatable(mtcars)reactable::reactable(mtcars)```Then execute `render_tabset()`. To make the results easier to see, sections are also to be added.```{r}#| results: asistables |>render_tabset(c(cyl, am),c( section_kable, kable, section_gt, gt, section_gt_interactive, gt_interactive, section_tt, tt, section_flex, flex, section_DT, DT, section_reac, reac ) )```<details><summary>Session Info</summary>```{r}# save the session info as an objectsess <- sessioninfo::session_info(pkgs ="attached")# inject the quarto infosess$platform$quarto <-paste( quarto::quarto_version(),"@", fs::path_real(quarto::quarto_path()))# print it outsess```</details>